<script setup>
import { ref, reactive, computed, onMounted,  watch, watchEffect, nextTick } from "vue";
import { aesEncrypt } from "./../utils/ase.js";
import { myRequest } from "../utils/request.js";

const emit = defineEmits(["success", "error", "ready"]); // 事件触发
const props = defineProps({
  mode: { type: String, default: "fixed" }, // 弹出模式
  captchaType: { type: String },
  vSpace: { type: Number, default: 5 },
  imgSize: {
    type: Object,
    default: () => ({ width: "310px", height: "155px" }),
  },
  barSize: {
    type: Object,
    default: () => ({ width: "310px", height: "40px" }),
  },
  defaultImg: { type: String, default: "" },
});

// ✅ 代替 data() 的变量
const checkNum = 3;
const fontPos = ref([]);
const checkPosArr = ref([]);
const num = ref(1);
const pointBackImgBase = ref("");
const poinTextList = ref([]);
const backToken = ref("");
const secretKey = ref("");
const imgLeft = ref("");
const imgTop = ref("");
const showImage = ref(true);
const tempPoints = ref([]);
const text = ref("");
const barAreaColor = ref("#fff");
const barAreaBorderColor = ref("#fff");
const showRefresh = ref(true);
const bindingClick = ref(true);
const canvas = ref(null); // 代替 Vue2 的 $refs.canvas

// ✅ 组件初始化
const init = async () => {
  fontPos.value = [];
  checkPosArr.value = [];
  num.value = 1;
  await nextTick();
  refresh();
  emit("ready");
};

// ✅ 刷新验证码
const refresh = () => {
  tempPoints.value = [];
  barAreaColor.value = "#000";
  barAreaBorderColor.value = "#ddd";
  bindingClick.value = true;
  fontPos.value = [];
  checkPosArr.value = [];
  num.value = 1;
  getPictrue();
  showRefresh.value = true;
};

// ✅ 获取验证码图片
const getPictrue = async () => {
  let data = {
    captchaType: props.captchaType,
    clientUid: uni.getStorageSync("point"),
    ts: Date.now(),
  };
  try {
    const result = await myRequest({
      url: "/admin-api/system/captcha/get",
      data,
      method: "POST",
    });
    let res = result.data;
    if (res.repCode === "0000") {
      pointBackImgBase.value = res.repData.originalImageBase64;
      backToken.value = res.repData.token;
      secretKey.value = res.repData.secretKey;
      poinTextList.value = res.repData.wordList;
      text.value = `请依次点击【${poinTextList.value.join(",")}】`;
    }
    if (res.repCode === "6201") {
      pointBackImgBase.value = null;
    }
  } catch (error) {
    console.error("获取验证码图片失败", error);
  }
};

// ✅ 计算点击位置
const getMousePos = (e) => {
  return {
    x: Math.ceil(e.detail.x) - imgLeft.value,
    y: Math.ceil(e.detail.y) - imgTop.value,
  };
};

// ✅ 处理点击验证码
const canvasClick = (e) => {
  const query = uni.createSelectorQuery().in(this);
  query.select("#image").boundingClientRect((data) => {
    imgLeft.value = Math.ceil(data.left);
    imgTop.value = Math.ceil(data.top);

    checkPosArr.value.push(getMousePos(e));
    if (num.value === checkNum) {
      num.value = createPoint(getMousePos(e));

      // 按比例转换坐标
      checkPosArr.value = pointTransfrom(checkPosArr.value, props.imgSize);

      setTimeout(async () => {
        let captchaVerification = secretKey.value
          ? aesEncrypt(
              `${backToken.value}---${JSON.stringify(checkPosArr.value)}`,
              secretKey.value
            )
          : `${backToken.value}---${JSON.stringify(checkPosArr.value)}`;

        let data = {
          captchaType: props.captchaType,
          pointJson: secretKey.value
            ? aesEncrypt(JSON.stringify(checkPosArr.value), secretKey.value)
            : JSON.stringify(checkPosArr.value),
          token: backToken.value,
        };

        try {
          const result = await myRequest({
            url: "/admin-api/system/captcha/check",
            data,
            method: "POST",
          });
          let res = result.data;
          if (res.repCode === "0000") {
            barAreaColor.value = "#4cae4c";
            barAreaBorderColor.value = "#5cb85c";
            text.value = "验证成功";
            bindingClick.value = false;
            setTimeout(() => {
              if (props.mode === "pop") {
                emit("close"); // 让父组件控制弹窗关闭
              }
              refresh();
            }, 1500);
            emit("success", { captchaVerification });
          } else {
            emit("error");
            barAreaColor.value = "#d9534f";
            barAreaBorderColor.value = "#d9534f";
            text.value = "验证失败";
            setTimeout(refresh, 700);
          }
        } catch (error) {
          console.error("验证码校验失败", error);
        }
      }, 400);
    }

    if (num.value < checkNum) {
      num.value = createPoint(getMousePos(e));
    }
  }).exec();
};

// ✅ 创建点击点
const createPoint = (pos) => {
  tempPoints.value.push({ ...pos });
  return ++num.value;
};

// ✅ 坐标转换
const pointTransfrom = (pointArr, imgSize) => {
  return pointArr.map((p) => ({
    x: Math.round((310 * p.x) / parseInt(imgSize.width)),
    y: Math.round((155 * p.y) / parseInt(imgSize.height)),
  }));
};

// ✅ 监听 captchaType 变化，自动刷新
watchEffect(() => {
  if (props.captchaType) {
    init();
  }
});

// ✅ 组件挂载后初始化
onMounted(() => {
  console.log("默认图片:", props.defaultImg);
  init();
});
</script>

<template>
  <view style="position: relative">
    <view class="verify-image-out" v-show="showImage">
      <view class="verify-image-panel" :style="{ width: imgSize.width, height: imgSize.height, marginBottom: vSpace + 'px' }">
        <view class="verify-refresh" style="z-index:3" @click="refresh" v-show="showRefresh">
          <text class="iconfont icon-refresh"></text>
        </view>
        <image :src="pointBackImgBase ? 'data:image/png;base64,' + pointBackImgBase : defaultImg"
          id="image" ref="canvas" style="width:100%;height:100%;display:block"
          @click="bindingClick ? canvasClick($event) : undefined">
        </image>
      </view>
    </view>
    <view class="verify-bar-area" :style="{ width: imgSize.width, color: barAreaColor, borderColor: barAreaBorderColor, lineHeight: '40px' }">
      <text class="verify-msg">{{ text }}</text>
    </view>
  </view>
</template>


<style scoped>
	.verifybox {
		position: relative;
		box-sizing: border-box;
		border-radius: 2px;
		border: 1px solid #e4e7eb;
		background-color: #fff;
		box-shadow: 0 0 10px rgba(0, 0, 0, .3);
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
	}

	.verifybox-top {
		padding: 0 15px;
		height: 50px;
		line-height: 50px;
		text-align: left;
		font-size: 16px;
		color: #45494c;
		border-bottom: 1px solid #e4e7eb;
		box-sizing: border-box;
	}

	.verifybox-bottom {
		/* padding: 15px; */
		box-sizing: border-box;
	}

	.verifybox-close {
		position: absolute;
		top: 13px;
		right: 9px;
		width: 24px;
		height: 24px;
		text-align: center;
		cursor: pointer;
	}

	.mask {
		position: fixed;
		top: 0;
		left: 0;
		z-index: 1001;
		width: 100%;
		height: 100vh;
		background: rgba(0, 0, 0, .3);
		/* display: none; */
		transition: all .5s;
	}

	.verify-tips {
		position: absolute;
		left: 0px;
		bottom: 0px;
		width: 100%;
		height: 30px;
		background-color: rgb(231, 27, 27, .5);
		line-height: 30px;
		color: #fff;
	}

	.tips-enter,
	.tips-leave-to {
		bottom: -30px;
	}

	.tips-enter-active,
	.tips-leave-active {
		transition: bottom .5s;
	}

	/* ---------------------------- */
	/*常规验证码*/
	.verify-code {
		font-size: 20px;
		text-align: center;
		cursor: pointer;
		margin-bottom: 5px;
		border: 1px solid #ddd;
	}

	.cerify-code-panel {
		height: 100%;
		overflow: hidden;
	}

	.verify-code-area {
		float: left;
	}

	.verify-input-area {
		float: left;
		width: 60%;
		padding-right: 10px;

	}

	.verify-change-area {
		line-height: 30px;
		float: left;
	}

	.varify-input-code {
		display: inline-block;
		width: 100%;
		height: 25px;
	}

	.verify-change-code {
		color: #337AB7;
		cursor: pointer;
	}

	.verify-btn {
		width: 200px;
		height: 30px;
		background-color: #337AB7;
		color: #FFFFFF;
		border: none;
		margin-top: 10px;
	}


	/*滑动验证码*/
	.verify-bar-area {
		position: relative;
		background: #FFFFFF;
		text-align: center;
		-webkit-box-sizing: content-box;
		-moz-box-sizing: content-box;
		box-sizing: content-box;
		border: 1px solid #ddd;
		-webkit-border-radius: 4px;
	}

	.verify-bar-area .verify-move-block {
		position: absolute;
		top: 0px;
		left: 0;
		background: #fff;
		cursor: pointer;
		-webkit-box-sizing: content-box;
		-moz-box-sizing: content-box;
		box-sizing: content-box;
		box-shadow: 0 0 2px #888888;
		-webkit-border-radius: 1px;
	}

	.verify-bar-area .verify-move-block:hover {
		background-color: #337ab7;
		color: #FFFFFF;
	}

	.verify-bar-area .verify-left-bar {
		position: absolute;
		top: -1px;
		left: -1px;
		background: #f0fff0;
		cursor: pointer;
		-webkit-box-sizing: content-box;
		-moz-box-sizing: content-box;
		box-sizing: content-box;
		border: 1px solid #ddd;
	}

	.verify-image-panel {
		margin: 0;
		-webkit-box-sizing: content-box;
		-moz-box-sizing: content-box;
		box-sizing: content-box;
		border-top: 1px solid #ddd;
		border-bottom: 1px solid #ddd;
		border-radius: 3px;
		position: relative;
	}

	.verify-image-panel .verify-refresh {
		width: 25px;
		height: 25px;
		text-align: center;
		padding: 5px;
		cursor: pointer;
		position: absolute;
		top: 0;
		right: 0;
		z-index: 2;
	}

	.verify-image-panel .icon-refresh {
		font-size: 20px;
		color: #fff;
	}

	.verify-image-panel .verify-gap {
		background-color: #fff;
		position: relative;
		z-index: 2;
		border: 1px solid #fff;
	}

	.verify-bar-area .verify-move-block .verify-sub-block {
		position: absolute;
		text-align: center;
		z-index: 3;
		/* border: 1px solid #fff; */
	}

	.verify-bar-area .verify-move-block .verify-icon {
		font-size: 18px;
	}

	.verify-bar-area .verify-msg {
		z-index: 3;
	}

	/*字体图标的css*/
	/*@font-face {font-family: "iconfont";*/
	/*src: url('../fonts/iconfont.eot?t=1508229193188'); !* IE9*!*/
	/*src: url('../fonts/iconfont.eot?t=1508229193188#iefix') format('embedded-opentype'), !* IE6-IE8 *!*/
	/*url('data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAaAAAsAAAAACUwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAADMAAABCsP6z7U9TLzIAAAE8AAAARAAAAFZW7kiSY21hcAAAAYAAAAB3AAABuM+qBlRnbHlmAAAB+AAAAnQAAALYnrUwT2hlYWQAAARsAAAALwAAADYPNwajaGhlYQAABJwAAAAcAAAAJAfeA4dobXR4AAAEuAAAABMAAAAYF+kAAGxvY2EAAATMAAAADgAAAA4CvAGsbWF4cAAABNwAAAAfAAAAIAEVAF1uYW1lAAAE/AAAAUUAAAJtPlT+fXBvc3QAAAZEAAAAPAAAAE3oPPXPeJxjYGRgYOBikGPQYWB0cfMJYeBgYGGAAJAMY05meiJQDMoDyrGAaQ4gZoOIAgCKIwNPAHicY2Bk/sM4gYGVgYOpk+kMAwNDP4RmfM1gxMjBwMDEwMrMgBUEpLmmMDgwVDxbwtzwv4EhhrmBoQEozAiSAwAw1A0UeJzFkcENgCAMRX8RjCGO4gTe9eQcnhzAfXC2rqG/hYsT8MmD9gdS0gJIAAaykAjIBYHppCvuD8juR6zMJ67A89Zdn/f1aNPikUn8RvYo8G20CjKim6Rf6b9m34+WWd/vBr+oW8V6q3vF5qKlYrPRp4L0Ad5nGL8AeJxFUc9rE0EYnTezu8lMsrvtbrqb3TRt0rS7bdOmdI0JbWmCtiItIv5oi14qevCk9SQVLFiQgqAF8Q9QLKIHLx48FkHo3ZNnFUXwD5C2B6dO6sFhmI83w7z3fe8RnZCjb2yX5YlLhskkmScXCIFRxYBFiyjH9Rqtoqes9/g5i8WVuJyqDNTYLPwBI+cljXrkGynDhoU+nCgnjbhGY5yst+gMEq8IBIXwsjPU67CnEPm4b0su0h309Fd67da4XBhr55KSm17POk7gOE/Shq6nKdVsC7d9j+tcGPKVboc9u/0jtB/ZIA7PXTVLBef6o/paccjnwOYm3ELJetPuDrvV3gg91wlSXWY6H5qVwRzWf2TybrYYfSdqoXOwh/Qa8RWIjBTiSI3h614/vKSNRhONOrsnQi6Xf4nQFQDTmJE1NKbhI6crHEJO/+S5QPxhYJRRyvBFBP+5T9EPpEAIVzzRQIrjmJ6jY1WTo+NXTMchuBsKuS8PRZATSMl9oTA4uNLkeIA0V1UeqOoGQh7IAxGo+7T83fn3T+voqCNPPAUazUYUI7LgKSV1Jk2oUeghYGhZ+cKOe2FjVu5ZKEY2VkE13AK1+jI4r1KLbPlZfrKiPhOXKPRj7q9sj9XJ7LFHNmrKJS3VCdhXGSdKrtmoQaWeMjQVt0KD6sGPOx0oH2fgtzoNROxtNq8F3tzYM/n+TjKSX5qf2jx941276TIr9FjXxKr8eX/6bK4yuopwo9py1sw8F9kdw4AmurRpLUM3tYx5ZnKpfHPi8dzz19vJ6MjyxYUrpqeb1uLs3eGV6vr21pSqpeWkqonAN9oUyIiXpv8XvlN5e3icY2BkYGAA4n0vN4fG89t8ZeBmYQCBa9wPPRH0/wcsDMwmQC4HAxNIFABAfAqaAHicY2BkYGBu+N/AEMPCAAJAkpEBFbABAEcMAm94nGNhYGBgfsnAwMKAigESnwEBAAAAAAAAdgCkANoBCAFsAAB4nGNgZGBgYGMIZGBlAAEmIOYCQgaG/2A+AwARSAFzAHicZY9NTsMwEIVf+gekEqqoYIfkBWIBKP0Rq25YVGr3XXTfpk6bKokjx63UA3AejsAJOALcgDvwSCebNpbH37x5Y08A3OAHHo7fLfeRPVwyO3INF7gXrlN/EG6QX4SbaONVuEX9TdjHM6bCbXRheYPXuGL2hHdhDx18CNdwjU/hOvUv4Qb5W7iJO/wKt9Dx6sI+5l5XuI1HL/bHVi+cXqnlQcWhySKTOb+CmV7vkoWt0uqca1vEJlODoF9JU51pW91T7NdD5yIVWZOqCas6SYzKrdnq0AUb5/JRrxeJHoQm5Vhj/rbGAo5xBYUlDowxQhhkiMro6DtVZvSvsUPCXntWPc3ndFsU1P9zhQEC9M9cU7qy0nk6T4E9XxtSdXQrbsuelDSRXs1JErJCXta2VELqATZlV44RelzRiT8oZ0j/AAlabsgAAAB4nGNgYoAALgbsgI2RiZGZkYWRlZGNkZ2BsYI1OSM1OZs1OSe/OJW1KDM9o4S9KDWtKLU4g4EBAJ79CeQ=') format('woff'),*/
	/*url('../fonts/iconfont.ttf?t=1508229193188') format('truetype'), !* chrome, firefox, opera, Safari, Android, iOS 4.2+*!*/
	/*url('../fonts/iconfont.svg?t=1508229193188#iconfont') format('svg'); !* iOS 4.1- *!*/
	/*}*/

	.iconfont {
		font-family: "iconfont" !important;
		font-size: 16px;
		font-style: normal;
		-webkit-font-smoothing: antialiased;
		-moz-osx-font-smoothing: grayscale;
	}

	.icon-check:before {
		content: " ";
		display: block;
		width: 16px;
		height: 16px;
		position: absolute;
		margin: auto;
		left: 0;
		right: 0;
		top: 0;
		bottom: 0;
		z-index: 9999;
		background-image: url("");
		background-size: contain;
	}

	.icon-close:before {
		content: " ";
		display: block;
		width: 16px;
		height: 16px;
		position: absolute;
		margin: auto;
		left: 0;
		right: 0;
		top: 0;
		bottom: 0;
		z-index: 9999;
		background-image: url("");
		background-size: contain;
	}

	.icon-right:before {
		content: " ";
		display: block;
		width: 16px;
		height: 16px;
		position: absolute;
		margin: auto;
		left: 0;
		right: 0;
		top: 0;
		bottom: 0;
		background-size: cover;
		z-index: 9999;
		background-image: url("");
		background-size: contain;
	}

	.icon-refresh:before {
		content: " ";
		display: block;
		width: 16px;
		height: 16px;
		position: absolute;
		margin: auto;
		left: 0;
		right: 0;
		top: 0;
		bottom: 0;
		z-index: 9999;
		background-image: url("");
		background-size: contain;
	}
</style>
